let _x: number = 0.0;
let _y: number = 0.0;
let _z: number = 0.0;
let _w: number = 0.0;
const EPSILON = 0.000001;
export class VectorHelper {
    static MoveTowardsV2(out: IVector2Like, pos: IVector2Like, targetPos: IVector2Like, clampedDistance: number) {
        out.x = targetPos.x - pos.x; out.y = targetPos.y - pos.y;
        let sqrDelta = this.SqrMagV2(out);
        let sqrClampedDistance = clampedDistance * clampedDistance;
        if (sqrDelta > sqrClampedDistance) {
            let deltaMag = Math.sqrt(sqrDelta)
            if (deltaMag > EPSILON) {
                this.MultiplyScalarV2(out, out, 1 / deltaMag * clampedDistance);
                this.AddV2(out, pos, out);
            }
            else {
                out.x = pos.x; out.y = pos.y;
            }

        }
        else {
            out.x = targetPos.x; out.y = targetPos.y;
        }
        return out;
    }
    static AddV2(out: IVector2Like, a: IVector2Like, b: IVector2Like) {
        out.x = a.x + b.x;
        out.y = a.y + b.y;
        return out;
    }
    static SubV2(out: IVector2Like, a: IVector2Like, b: IVector2Like) {
        out.x = a.x - b.x;
        out.y = a.y - b.y;
        return out;
    }
    static MagV2(v2: IVector2Like) {
        _x = v2.x;
        _y = v2.y;
        return Math.sqrt(_x * _x + _y * _y);
    }
    static SqrMagV2(v3: IVector2Like) {
        _x = v3.x;
        _y = v3.y;
        return _x * _x + _y * _y;
    }
    static MultiplyScalarV2(out: IVector2Like, a: IVector2Like, b: number) {
        out.x = a.x * b;
        out.y = a.y * b;
        return out;
    }
    static MultiplyV2(out: IVector2Like, a: IVector2Like, b: IVector2Like) {
        out.x = a.x * b.x;
        out.y = a.y * b.y;
        return out;
    }
    static NormalizeV2(out: IVector2Like, a: IVector2Like) {
        _x = a.x;
        _y = a.y;
        let len = _x * _x + _y * _y;
        if (len > 0) {
            len = 1 / Math.sqrt(len);
            out.x = _x * len;
            out.y = _y * len;
        }
        return out;
    }
    static DotV2(a: IVector2Like, b: IVector2Like) {
        return a.x * b.x + a.y * b.y;
    }
    static LerpV2(out: IVec2Like, a: IVec2Like, b: IVec2Like, t: number) {
        out.x = a.x + t * (b.x - a.x);
        out.y = a.y + t * (b.y - a.y);
        return out;
    }
    static RandomV2(out: IVec2Like, scale?: number) {
        scale = scale || 1.0;
        const phi = Math.random() * 2.0 * Math.PI;
        out.x = Math.cos(phi) * scale;
        out.y = Math.sin(phi) * scale;
        return out;
    }
    static LookAtAngle(selfAangle: number, selfPos: IVec2Like, targetPos: IVec2Like) {
        let dx = targetPos.x - selfPos.x;
        let dy = targetPos.y - selfPos.y;
        let rotationZ = Math.atan2(dy, dx) * 180 / Math.PI;
        //得到最终的角度并且确保在 [0, 360) 这个区间内
        //rotationZ -= 90;
        //获取增加的角度
        let originRotationZ = selfAangle;
        let addRotationZ = rotationZ - originRotationZ;
        //超过 180 度需要修改为负方向的角度
        if (addRotationZ > 180) {
            addRotationZ -= 360;
        }
        return selfAangle + addRotationZ;
    }
    static InRect(point: IVector2Like, rect: RectLike) {
        _x = point.x - rect.x; _y = point.y - rect.y;
        _z = rect.width / 2; _w = rect.height / 2;
        return Math.abs(_x) <= _z && Math.abs(_y) <= _w;
    }
    /**
    * 点是否在圆内部
    *@param checkPos 检查点
    *@param center 圆心点
    *@param radius 半径
    */
    static InCircle(checkPos: IVector2Like, center: IVector2Like, radius: number) {
        _x = checkPos.x - center.x;
        _y = checkPos.y - center.y;
        return _x * _x + _y * _y < radius * radius;
    }
    /**
 * 获取两点间的角度
 * @param p1 点1
 * @param p2 点2
 */
    static GetAngle(p1: IVector2Like, p2: IVector2Like): number {
        return Math.atan((p2.y - p1.y) / (p2.x - p1.x));
    }
    static MoveTowardsV3(out: IVector3Like, pos: IVector3Like, targetPos: IVector3Like, clampedDistance: number) {
        out.x = targetPos.x - pos.x; out.y = targetPos.y - pos.y; out.z = targetPos.z - pos.z;
        let sqrDelta = this.SqrMagV3(out);
        let sqrClampedDistance = clampedDistance * clampedDistance;
        if (sqrDelta > sqrClampedDistance) {
            let deltaMag = Math.sqrt(sqrDelta)
            if (deltaMag > EPSILON) {
                this.MultiplyScalarV3(out, out, 1 / deltaMag * clampedDistance);
                this.AddV3(out, pos, out);
            }
            else {
                out.x = pos.x; out.y = pos.y; out.z = pos.z;
            }

        }
        else {
            out.x = targetPos.x; out.y = targetPos.y; out.z = targetPos.z;
        }
        return out;
    }
    static MagV3(v3: IVector3Like) {
        _x = v3.x;
        _y = v3.y;
        _z = v3.z;
        return Math.sqrt(_x * _x + _y * _y + _z * _z);
    }
    static SqrMagV3(v3: IVector3Like) {
        _x = v3.x;
        _y = v3.y;
        _z = v3.z;
        return _x * _x + _y * _y + _z * _z;
    }
    static MultiplyScalarV3(out: IVector3Like, a: IVector3Like, b: number) {
        out.x = a.x * b;
        out.y = a.y * b;
        out.z = a.z * b;
        return out;
    }
    static MultiplyV3(out: IVector3Like, a: IVector3Like, b: IVector3Like) {
        out.x = a.x * b.x;
        out.y = a.y * b.y;
        out.z = a.z * b.z;
        return out;
    }
    static AddV3(out: IVector3Like, a: IVector3Like, b: IVector3Like) {
        out.x = a.x + b.x;
        out.y = a.y + b.x;
        out.z = a.z + b.x;
        return out;
    }
    static SubV3(out: IVector3Like, a: IVector3Like, b: IVector3Like) {
        out.x = a.x - b.x;
        out.y = a.y - b.x;
        out.z = a.z - b.x;
        return out;
    }
    static NormalizeV3(out: IVector3Like, a: IVector3Like) {
        _x = a.x;
        _y = a.y;
        _z = a.z;
        let len = _x * _x + _y * _y + _z * _z;
        if (len > 0) {
            len = 1 / Math.sqrt(len);
            out.x = _x * len;
            out.y = _y * len;
            out.z = _z * len;
        }
        return out;
    }
    static DotV3(a: IVector3Like, b: IVector3Like) {
        return a.x * b.x + a.y * b.y + a.z * b.z;
    }
    static CrossV3(out: IVector3Like, a: IVector3Like, b: IVector3Like) {
        const { x: ax, y: ay, z: az } = a;
        const { x: bx, y: by, z: bz } = b;
        out.x = ay * bz - az * by;
        out.y = az * bx - ax * bz;
        out.z = ax * by - ay * bx;
        return out;
    }
    static LerpV3(out: IVec3Like, a: IVec3Like, b: IVec3Like, t: number) {
        out.x = a.x + t * (b.x - a.x);
        out.y = a.y + t * (b.y - a.y);
        out.z = a.z + t * (b.z - a.z);
        return out;
    }
    static RandomV3(out: IVec3Like, scale?: number) {
        scale = scale || 1.0;

        const phi = Math.random() * 2.0 * Math.PI;
        const cosTheta = Math.random() * 2 - 1;
        const sinTheta = Math.sqrt(1 - cosTheta * cosTheta);

        out.x = sinTheta * Math.cos(phi) * scale;
        out.y = sinTheta * Math.sin(phi) * scale;
        out.z = cosTheta * scale;
        return out;
    }
}
interface IVector2Like {
    x: number, y: number
}
interface IVector3Like {
    x: number, y: number, z: number
}
interface IVector4Like {
    x: number, y: number, z: number, w: number
}
interface RectLike {
    x: number; y: number; width: number; height: number;
}
